
#include    "memory_allocation.h"

/* Near status handling variables*/
const NearMemAlloc_ConfigType * mem_alloc_nearcnf;

NearMemAlloc_StatusType    NearMemAlloc_Status;

NearRAM_StatusType NearRamPages_status[MEM_ALLOC_MAX_NEAR_RAM_PAGES] = 
{
    {RAM_NULL, (tu8Ptr_Near)NULL,(tu8Ptr_Near)NULL, 0}
};
/* Far status handling variables*/
const MemAlloc_ConfigType * mem_alloc_farcnf;
MemAlloc_StatusType    MemAlloc_Status;

PagedRAM_StatusType PagedRamPagesFar_status[MEM_ALLOC_MAX_FAR_RAM_PAGES] = 
{
    {RAM_NULL, (tu8Ptr_Far)NULL,(tu8Ptr_Far)NULL, 0},
    {RAM_NULL, (tu8Ptr_Far)NULL,(tu8Ptr_Far)NULL, 0}
};


void vfnMemAlloc_NearInit( const NearMemAlloc_ConfigType * mem_alloc_config  )
{
    uint8_t u8pageIndex;
    tu8Ptr_Near StartAddress;
    tu8Ptr_Near EndAddress;
    
    /* Store pointer to driver configuration */
    mem_alloc_nearcnf = mem_alloc_config;
    
    NearMemAlloc_Status.RamPageStatus = &NearRamPages_status[0];
    
    if (mem_alloc_nearcnf->u8Number_of_RAM_pages != 0)
    {
        for (u8pageIndex = 0; u8pageIndex < mem_alloc_nearcnf->u8Number_of_RAM_pages; u8pageIndex++ )
        {
            /* Obtain Start and End Addresses */
            StartAddress =   mem_alloc_nearcnf->ptr_NearRAMpages_config[u8pageIndex].ptr_nearStartAddress;
            EndAddress = mem_alloc_nearcnf->ptr_NearRAMpages_config[u8pageIndex].ptr_nearEndAddress;
            /* Update all relevant entries in status structure */ 
            NearMemAlloc_Status.RamPageStatus[u8pageIndex].RamPageId = mem_alloc_nearcnf->ptr_NearRAMpages_config[u8pageIndex].RamPageId;
            NearMemAlloc_Status.RamPageStatus[u8pageIndex].ptr_nearCurrentAddress = StartAddress;
            NearMemAlloc_Status.RamPageStatus[u8pageIndex].ptr_nearEndAddress = EndAddress;
            NearMemAlloc_Status.RamPageStatus[u8pageIndex].u16_FreeBytes = (uint16_t)(EndAddress - StartAddress + 1);
            /* Updated internal variable that keeps track of available pages */
            NearMemAlloc_Status.u8NumberOfPages++;
            
            /* Erase RAM in order to assure all entries are ready to be used */
            vfnMemAlloc_NearErase(StartAddress, NearMemAlloc_Status.RamPageStatus[u8pageIndex].u16_FreeBytes);
        }
    }
}


tu8Ptr_Near MemAlloc_NearReserve( uint16_t  u16SizeinBytes)
{
    uint8_t u8pageIndex;
    tu8Ptr_Near prtAllocatedBuffer = (tu8Ptr_Near)NULL;
    static tu8Ptr_Near nearStartAddress;
    static tu8Ptr_Near nearEndAddress;
    
    for (u8pageIndex = 0; u8pageIndex < NearMemAlloc_Status.u8NumberOfPages; u8pageIndex++ )
    {
        /* Get start and end address parameters for this RAM page */ 
        nearStartAddress = NearMemAlloc_Status.RamPageStatus[u8pageIndex].ptr_nearCurrentAddress;
        nearEndAddress = NearMemAlloc_Status.RamPageStatus[u8pageIndex].ptr_nearEndAddress;
        /* Apply alginment */
        nearStartAddress = (tu8Ptr_Near)(((uint16_t)(nearStartAddress)+3) & (uint16_t)MEM_ALLOC_4_BYTE_ALIGN);
        /* Verify if enough memory is free */
        if( (uint16_t)(nearEndAddress - nearStartAddress + 1) >= u16SizeinBytes )
        {
            /* Enough memory is available, reserve it and return its start address */
            prtAllocatedBuffer = nearStartAddress;
            NearMemAlloc_Status.RamPageStatus[u8pageIndex].ptr_nearCurrentAddress = nearStartAddress + u16SizeinBytes;
            NearMemAlloc_Status.RamPageStatus[u8pageIndex].u16_FreeBytes = (uint16_t)(nearEndAddress - nearStartAddress - u16SizeinBytes + 1);
            /* Stop searching thorugh pages */
            break;
        }
    }
    
    return(prtAllocatedBuffer);
}


void vfnMemAlloc_NearErase( tu8Ptr_Near StartAddress , uint16_t  u16SizeinBytes)
{
    uint16_t u16Bytes;
    
    for (u16Bytes = 0; u16Bytes < u16SizeinBytes; u16Bytes++ )
    {
        *StartAddress++ = 0x00;
    }
}

void vfnMemAlloc_Init( const MemAlloc_ConfigType * mem_alloc_config  )
{
    uint8_t u8pageIndex;
    tu8Ptr_Far StartAddress;
    tu8Ptr_Far EndAddress;
    
    /* Store pointer to driver configuration */
    mem_alloc_farcnf = mem_alloc_config;
    
    MemAlloc_Status.RamPageStatus = &PagedRamPagesFar_status[0];
    
    if (mem_alloc_farcnf->u8Number_of_RAM_pages != 0)
    {
        for (u8pageIndex = 0; u8pageIndex < mem_alloc_farcnf->u8Number_of_RAM_pages; u8pageIndex++ )
        {
            /* Obtain Start and End Addresses */
            StartAddress =   mem_alloc_farcnf->ptr_PagedRAMpages_config[u8pageIndex].ptr_StartAddress;
            EndAddress = mem_alloc_farcnf->ptr_PagedRAMpages_config[u8pageIndex].ptr_EndAddress;
            /* Update all relevant entries in status structure */ 
            MemAlloc_Status.RamPageStatus[u8pageIndex].RamPageId = mem_alloc_farcnf->ptr_PagedRAMpages_config[u8pageIndex].RamPageId;
            MemAlloc_Status.RamPageStatus[u8pageIndex].ptr_CurrentAddress = StartAddress;
            MemAlloc_Status.RamPageStatus[u8pageIndex].ptr_EndAddress = EndAddress;
            MemAlloc_Status.RamPageStatus[u8pageIndex].u16_FreeBytes = (uint16_t)(EndAddress - StartAddress + 1);
            /* Updated internal variable that keeps track of available pages */
            MemAlloc_Status.u8NumberOfPages++;
            
            /* Erase RAM in order to assure all entries are ready to be used */
            vfnMemAlloc_Erase(StartAddress, MemAlloc_Status.RamPageStatus[u8pageIndex].u16_FreeBytes);
        }
    }
}


tu8Ptr_Far MemAlloc_Reserve( uint16_t  u16SizeinBytes)
{
    uint8_t u8pageIndex;
    tu8Ptr_Far prtAllocatedBuffer = (tu8Ptr_Far)NULL;
    static tu8Ptr_Far farStartAddress;
    static tu8Ptr_Far farEndAddress;
    
    for (u8pageIndex = 0; u8pageIndex < MemAlloc_Status.u8NumberOfPages; u8pageIndex++ )
    {
        /* Get start and end address parameters for this RAM page */ 
        farStartAddress = MemAlloc_Status.RamPageStatus[u8pageIndex].ptr_CurrentAddress;
        farEndAddress = MemAlloc_Status.RamPageStatus[u8pageIndex].ptr_EndAddress;
        /* Apply alginment */
        farStartAddress = (tu8Ptr_Far)(((uint32_t)(farStartAddress)+3) & (uint32_t)MEM_ALLOC_4_BYTE_ALIGN);
        /* Verify if enough memory is free */
        if( (uint16_t)(farEndAddress - farStartAddress + 1) >= u16SizeinBytes )
        {
            /* Enough memory is available, reserve it and return its start address */
            prtAllocatedBuffer = farStartAddress;
            MemAlloc_Status.RamPageStatus[u8pageIndex].ptr_CurrentAddress = farStartAddress + u16SizeinBytes;
            MemAlloc_Status.RamPageStatus[u8pageIndex].u16_FreeBytes = (uint16_t)(farEndAddress - farStartAddress + 1);
            /* Stop searching thorugh pages */
            break;
        }
    }
    
    return(prtAllocatedBuffer);
}


void vfnMemAlloc_Erase( tu8Ptr_Far StartAddress , uint16_t  u16SizeinBytes)
{
    uint16_t u16Bytes;
    
    for (u16Bytes = 0; u16Bytes < u16SizeinBytes; u16Bytes++ )
    {
        *StartAddress++ = 0x00;
    }
}

